namespace EyeSoft.Wpf.Facilities.Demo.ViewModels
{
	using System;
	using System.Collections.Generic;
	using System.Threading;
	using System.Windows;
	using System.Windows.Input;

	using EyeSoft.Messanging;
	using EyeSoft.Timers;
	using EyeSoft.Validation;
	using EyeSoft.Wpf.Facilities;
	using EyeSoft.Wpf.Facilities.Collection.Property;
	using EyeSoft.Wpf.Facilities.Collections.ObjectModel;
	using EyeSoft.Wpf.Facilities.Demo.Contract;

	public class MainViewModel : AutoRegisterViewModel
	{
		private readonly ServiceFactory<ICustomerService> serviceFactory;

		private readonly ITimerFactory timerFactory;

		public MainViewModel()
		{
			serviceFactory = ViewModelController.ServiceFactory<ICustomerService>();
			timerFactory = ViewModelController.TimerFactory();

			MessageBroker.Register<DeleteCustomerMessage>(this, DeleteCustomer);

			ReactPropertyChanged(() => FullName, x => NameLength = x.Length);

			InitializeProperties();
		}

		~MainViewModel()
		{
			Dispose();
		}

		public string FullName
		{
			get { return GetProperty<string>(); }
			set { SetProperty(value); }
		}

		public int NameLength
		{
			get { return GetProperty<int>(); }
			private set { SetProperty(value); }
		}

		public CustomerViewModel MainCustomer
		{
			get { return GetProperty<CustomerViewModel>(); }
			set { SetProperty(value); }
		}

		public SmartObservableCollection<CustomerViewModel> CustomerCollection { get; set; }

		public ICommand ShowChildCommand { get; private set; }

		public ICommand ReloadCommand { get; private set; }

		public override bool CanClose()
		{
			if (!IsValid)
			{
				DialogService.ShowMessage("Data not valid", "The data must be valid.");
			}

			return base.CanClose();
		}

		protected void ShowChild()
		{
			Thread.Sleep(2000);

			var nameTokens = FullName.Trim().Split();
			var editCustomerViewModel = new EditCustomerViewModel(new CustomerViewModel(nameTokens[0], nameTokens[1]));
			var result = DialogService.ShowModal<EditCustomerViewModel, string>(editCustomerViewModel);

			DialogService.ShowMessage("Window closed", "Value returned:\r\n" + result);
		}

		protected bool CanShowChild()
		{
			return !string.IsNullOrWhiteSpace(FullName) && IsValid;
		}

		protected override IEnumerable<ValidationError> Validate()
		{
			return new MainViewModelValidator().Validate(this);
		}

		protected void Reload()
		{
			LoadFromService();
		}

		private void InitializeProperties()
		{
			LoadFromService()
				.Completed(
					collection =>
					{
						collection.Add(new CustomerViewModel("Added after", "Completed"));

						SimulateEditingAndUpdateAnItem(collection);
					});

			serviceFactory
				.Property(this, x => x.MainCustomer)
				.Fill(x => x.GetMainCustomer())
				.Completed(
					x =>
						{
							x.Visits++;

							serviceFactory
								.With(MainCustomer)
								.Execute<CustomerDto>((service, entity) => service.Save(entity))
								.Completed(viewModel => DialogService.ShowMessage("Saved", "Save completed"));
						});
		}

		private ICollectionFilled<CustomerViewModel> LoadFromService()
		{
			return
				serviceFactory
					.Collection(this, x => x.CustomerCollection)
					.Sort((x, y) => string.Compare(x.FirstName, y.FirstName, StringComparison.Ordinal))
					.Fill(x => x.GetCustomersWithTurnoverGreatherThan(1000));
		}

		private void SimulateEditingAndUpdateAnItem(SmartObservableCollection<CustomerViewModel> collection)
		{
			Action action =
				() =>
				{
					var collectionView = collection.ListView();

					var index = collectionView.Count - 1;
					var item = (CustomerViewModel)collectionView.GetItemAt(index);
					item = new CustomerViewModel(item.FirstName.ToUpper(), item.LastName);

					serviceFactory
						.With(item)
						.Execute<CustomerDto>((service, entity) => service.Save(entity))
						.UpdateCollection(collection);

					timerFactory.DelayedExecute(2000, () => CustomerCollection.InvertSort());
				};

			timerFactory.DelayedExecute(3000, action);
		}

		private void DeleteCustomer(DeleteCustomerMessage deleteCustomerMessage)
		{
			var confirmDeleteCustomer = DialogService.ShowMessage("Delete customer", "Confirm deletion?", MessageBoxButton.YesNo);

			if (confirmDeleteCustomer == MessageBoxResult.No)
			{
				return;
			}

			serviceFactory.Execute(service => service.Delete(deleteCustomerMessage.Customer.Id));
			CustomerCollection.Remove(deleteCustomerMessage.Customer);
		}
	}
}